package com.jec.module.sysmonitor.service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import com.jec.module.sysconfig.service.Configors;
import com.jec.module.sysmanage.service.SysLogService;
import com.jec.module.sysmonitor.dao.CardRepository;
import com.jec.module.sysmonitor.dao.CardTypeRepository;
import com.jec.module.sysmonitor.dao.CardViewRepository;
import com.jec.module.sysmonitor.dao.NetConnectRepository;
import com.jec.module.sysmonitor.dao.NetUnitRepository;
import com.jec.module.sysmonitor.dao.TerminalDeviceRepository;
import com.jec.module.sysmonitor.dao.TerminalDeviceViewRepository;
import com.jec.module.sysmonitor.entity.Card;
import com.jec.module.sysmonitor.entity.CardType;
import com.jec.module.sysmonitor.entity.NetConnect;
import com.jec.module.sysmonitor.entity.NetUnit;
import com.jec.module.sysmonitor.entity.view.CardView;
import com.jec.module.sysmonitor.entity.view.TerminalDeviceView;
import com.jec.module.sysmonitor.vo.CardConfig;
import com.jec.module.sysmonitor.vo.Device;
import com.jec.module.sysmonitor.vo.NetTopo;
import com.jec.protocol.pdu.PduConstants;
import com.jec.protocol.pdu.ProtocolUtils;
import com.jec.utils.Response;

/**
 * Created by jeremyliu on 5/9/16.
 */

@Service
public class NetWorkMonitorService{

    @Autowired
    private NetUnitRepository netUnitRepository;
    
    @Autowired
    private CardRepository cardRepository;

    @Autowired
    private CardViewRepository cardViewRepository;

	@Autowired
    private TerminalDeviceViewRepository terminalDeviceViewRepository;

    @Autowired
    private CardTypeRepository cardTypeRepository;
    
    @Resource
    private TerminalDeviceRepository terminalDeviceRepository;
    
    @Autowired
    private NetConnectRepository netConnectRepository;
    
    @Autowired
    private Configors configors;

    @Resource
    private SysLogService sysLogService;


    @Transactional(readOnly = true)
    @PostConstruct
    public void refreshCaches(){
        if(!TransactionSynchronizationManager.isSynchronizationActive())
            TransactionSynchronizationManager.initSynchronization();
        List<NetUnit> netUnits = netUnitRepository.findAll();
        ProtocolUtils.setNetUnitCaches(netUnits);
    }

    @Transactional
    public int addNetUnit(String name, String location, int net, String ip, int port, int slotCount){
        try {
            NetUnit netUnit = new NetUnit();
            netUnit.setIp(ip);
            netUnit.setName(name);
            netUnit.setLocation(location);
            netUnit.setPort(port);
            netUnit.setCardCount(slotCount);

            if(netUnitRepository.findOneByNetId(net) != null)
                return -2;

            netUnit.setNetId(net);
            netUnitRepository.save(netUnit);

            //Card[] cards = new Card[slotCount];

            for (int i = 0; i < slotCount; i++) {
            	Card card = new Card();
                card.setNetUnitId(netUnit.getId());
                card.setSlotNumber(i+1);
                cardRepository.save(card);
            }
            
            refreshCaches();
            return netUnit.getId();
        }catch(Exception e){
            e.printStackTrace();
            return -1;
        }
    }

    @Transactional
    public int modifyNetUnit(int id, int netId, String name, String ip, int port, int slotCount, String location){
        if(id <= 0)
            return  -1;
        NetUnit netUnit = netUnitRepository.findOne(id);
        if(netUnit == null)
            return -1;

        //检查新的ip地址是否和其他的冲突
        if(netId != netUnit.getNetId() && netUnitRepository.findOneByNetId(netId) != null)
            return -2;

        netUnit.setName(name);
        netUnit.setPort(port);
        netUnit.setNetId(netId);
        netUnit.setIp(ip);
        netUnit.setLocation(location);

        //如果当前板卡数量比之前的数量少
        int diff = slotCount - netUnit.getCardCount();
        if(diff < 0){

            //查询板卡号大于slotCount的光传输板
        	/*
            Search search = new Search(Card.class);
            search.addFilterEqual("netUnitId", netId);
            search.addFilterEqual("type",PduConstants.CARD_TYPE_OTB);
            search.addFilterGreaterThan("slotNumber", slotCount);

            List<Card> cards = cardDao.search(search);
            */
        	List<Card> cards = cardRepository.findByNetUnitIdAndTypeAndSlotNumberGreaterThan(netId, PduConstants.CARD_TYPE_OTB, slotCount);
            List<Integer> cardSlots = new ArrayList<>(cards.size());

            for(Card card : cards){
                cardSlots.add(card.getSlotNumber());
            }
            //删除连接信息
            //netConnectDao.removeConnect(netId, cardSlots);
            netConnectRepository.deleteByDestIdAndSlotIn(netId, cardSlots);

            //删除板卡
            /*
            search.removeFiltersOnProperty("type");
            cards = cardDao.search(search);
            cardDao.remove(cards.toArray(new Card[cards.size()]));
            */
            cardRepository.deleteByNetUnitIdAndSlotNumberGreaterThan(netId, slotCount);
            
            netUnit.setCardCount(slotCount);
        }else{
            Card[] cards = new Card[diff];

            for (int i = 0; i < diff; i++) {
                cards[i] = new Card();
                cards[i].setNetUnitId(netUnit.getId());
                cards[i].setSlotNumber(i+1+netUnit.getCardCount());
            }
            for(Card c : cards)
            	cardRepository.save(c);
            netUnit.setCardCount(slotCount);
        }
        refreshCaches();
        return netId;
    }

    @Transactional
    public boolean saveNetConnect(int srcId, int destId, int slot, int port){
        NetUnit src = netUnitRepository.findOne(srcId);
        if(src == null)
            return false;
        NetUnit dest = netUnitRepository.findOne(destId);
        if(dest == null)
            return false;

        /*
        //判断是否配置光传输板
        Search search = new Search(CardView.class);
        search.addFilterEqual("netUnitId", destId);
        search.addFilterEqual("slot", slot);
        search.addFilterEqual("code", PduConstants.CARD_TYPE_OTB);
        search.addFilterGreaterOrEqual("portCount", port);

        if(cardViewDao.searchUnique(search) == null)
            return false;
        */
        
        CardView found = cardViewRepository.findOneByNetUnitIdAndSlotAndCodeAndPortCountGreaterThanEqual(
        		destId, slot, PduConstants.CARD_TYPE_OTB, port);
        if(found == null)
        	return false;

        /*
        NetConnectId netConnectId = new NetConnectId(srcId,destId);
        NetConnect netConnect = netConnectRepository.findOne(netConnectId);
        */
        NetConnect netConnect = netConnectRepository.findOneBySrcIdAndDestId(srcId, destId);

        if(netConnect == null) {
            netConnect = new NetConnect();
            netConnect.setSrcId(srcId);
            netConnect.setDestId(destId);
            netConnect.setSlot(slot);
            netConnect.setPort(port);
        }else{
            netConnect.setPort(port);
            netConnect.setSlot(slot);
        }

        netConnectRepository.save(netConnect);
        sysLogService.addLog("添加"+src.getName()+"到"+dest.getName()+"的连接配置");
        return true;
    }

    @Transactional(readOnly = true)
    public Map<String, Object> getNetUnitAndDevice(){
        List<NetUnit> netUnits = netUnitRepository.findAll();
        List<NetConnect> connect =  netConnectRepository.findAll();
        List<NetTopo> topo = new ArrayList<NetTopo>();

        for(NetUnit netUnit : netUnits){
            NetTopo netTopo = new NetTopo();
            netTopo.setName(netUnit.getName());
            netTopo.setId(netUnit.getId());
            netTopo.setNetid(netUnit.getNetId());
            netTopo.setLocation(netUnit.getLocation());

            List<TerminalDeviceView> terminals = terminalDeviceViewRepository.findAllByNetUnitId(netUnit.getId());
            List<Device> devices = new ArrayList<Device>();
            for(TerminalDeviceView terminal : terminals){
                Device device = new Device(terminal);
                devices.add(device);
            }
            netTopo.setDevices(devices);
            topo.add(netTopo);
        }
        Map<String, Object> map = new HashMap<>(2);
        map.put("device",topo);
        map.put("connect", connect);
        return map;
    }

    @Transactional(readOnly = true)
    public List<NetUnit> getAllNetUnit(){
        return netUnitRepository.findAll();
    }

    @Transactional(readOnly = true)
    public NetUnit getNetUnit(int id){
        return netUnitRepository.findOne(id);
    }

    @Transactional(readOnly = true)
    public List<CardConfig> getCardByNetUnit(int netUnitId){
    	
    	/*
        Search search = new Search();
        search.addFilterEqual("netUnitId", netUnitId);
        search.addSort("slot",false);
        List<CardView> cardViews = cardViewDao.search(search);
        */
        
        List<CardView> cardViews = cardViewRepository.findAllByNetUnitIdOrderBySlotAsc(netUnitId);
        List<CardConfig> cardConfigs = new ArrayList<>(cardViews.size());

        for(CardView cardView: cardViews) {
            CardConfig cardConfig = new CardConfig(cardView);
            cardConfigs.add(cardConfig);
        }
        return cardConfigs;
    }



    @Transactional
    public boolean modifyCard(int id,int type){
        Card card = cardRepository.findOne(id);
        if(card == null)
            return false;
        //CardType cardType = cardTypeDao.find(type);
        CardType cardType = cardTypeRepository.findOne(type);
        if(cardType == null)
            return false;
        card.setType(type);
        cardRepository.save(card);
        String name = netUnitRepository.findOne(card.getNetUnitId()).getName();
        sysLogService.addLog("修改"+name+"的"+card.getSlotNumber()+"号槽位板卡类型");
        return true;
    }

	@Transactional
    public Response removeNetUnit(int netUnitId){

        Response response = Response.Builder();
        try {
        	
        	if(configors.hasConfigOnNetunit(netUnitId))
        		return response.message("系统存在该网元的业务配置或设备配置,请先删除").status(Response.STATUS_FAIL);
        	
        	/*
            Search search = new Search();

            for(Map.Entry<Class<?>, BaseDao> entry: configService.getDaoMap().entrySet()){
                if(entry.getKey()== TerminalBusiness.class ||
                        entry.getKey() == TerminalKeyConfig.class)
                    continue;
                BaseDao dao = entry.getValue();
                search.clear();
                search.setSearchClass(entry.getKey());
                search.addFilterEqual("netunit", netUnitId);
                List list = dao.search(search);
                if(list.size()>0)
                    return response.message("系统存在该网元的业务配置或设备配置,请先删除").status(Response.STATUS_FAIL);
            }
            */
        	
            NetUnit netUnit = netUnitRepository.findOne(netUnitId);
            if(netUnit == null)
                return response.message("网元不存在").status(Response.STATUS_PARAM_ERROR);
            //terminalDeviceDao.removeDeviceByNetUnit(netUnitId);
            terminalDeviceRepository.deleteByNetUnitId(netUnitId);
            //cardDao.removeByNetUnit(netUnitId);
            cardRepository.deleteByNetUnitId(netUnitId);
            //netConnectDao.removeConnect(netUnitId);
            netConnectRepository.deleteBySrcIdOrDestId(netUnitId, netUnitId);
            //netUnitDao.removeById(netUnitId);
            netUnitRepository.delete(netUnitId);
            sysLogService.addLog("删除"+netUnit.getName());
            refreshCaches();
            return response.data(true);
        }catch (Exception e){
            e.printStackTrace();
            return response.status(Response.STATUS_SYS_ERROR).message("网元删除失败").data(false);
        }

    }

    /*
    @Transactional
    public List<TerminalDevice> getDeviceByCard(int cardId){
        Search search = new Search(TerminalDevice.class);
        search.addFilterEqual("cardId", cardId);
        return terminalDeviceDao.search(search);
    }
    */

    @Transactional
    public List<CardType> getAllCardType(){
        //return cardTypeDao.findAll();
    	return cardTypeRepository.findAll();
    }

    @Transactional
    public Map<Integer, CardType> getCardTypeMap(){
        List<CardType> cardTypes = cardTypeRepository.findAll();
        Map<Integer, CardType> map= new HashMap<Integer, CardType>();
        for(CardType cardType : cardTypes)
            map.put(cardType.getCode(), cardType);

        return map;
    }

    @Transactional
    public List<CardView> getNetUnitCardSlot(int netunit, int type){
    	/*
        Search search = new Search(CardView.class);
        search.addFilterEqual("netUnitId", netunit);
        if(type>=0)
            search.addFilterEqual("code", type);

        return cardViewDao.search(search);
        */
    	
    	
        if(type >= 0) {
        	
        	return cardViewRepository.findAllByNetUnitIdAndCode(netunit, type);
        	
        } else {
        	
        	return cardViewRepository.findAllByNetUnitIdOrderBySlotAsc(netunit);
        }
    }
}
